import React, { Component } from 'react';
import { Spin } from 'antd';
import { connect } from 'react-redux';
import ExpenseMain from './expense-main';
import ExpenseFooter from './expense-footer';
import baseService from 'share/base.service';
import ExpenseAdjunct from './expense-adjunct';
import Telescopic from './component/telescopic';
import { setCurrentExpense } from 'actions/expense';
import expenseReportService from '../expense-report/expense-report.service';
import ExpenseService from './expense-service';
import 'styles/expense/expense-new.scss';
import { checkMenuDisabled } from 'share/common';
import expenseService from '../my-account/expense.service';
import errorMessage from 'share/errorMessage';
import AuditExpenseDetail from '../financial-management/invoice-bag-approve/invoice-bag-approve-detail/audit-expense-detail';

const { TelescopicLeft, TelescopicRight } = Telescopic;

@connect(mapStateToProps)
class ExpenseDetail extends Component {

  static childContextTypes = {
    nowExpenseDataSource: React.PropTypes.array,
    annotates: React.PropTypes.array,
    isAuditEditable: React.PropTypes.bool,
    isWaitForAudit: React.PropTypes.bool,
    currentExpense: React.PropTypes.object,
    expenseReport: React.PropTypes.object,
    currentExpenseType: React.PropTypes.object,
    currentExpenseIndex: React.PropTypes.number,
    headerData: React.PropTypes.object,
    amountData: React.PropTypes.array,
    fieldsData: React.PropTypes.array,
    mergeAdjuncts: React.PropTypes.array,
    auditTab: React.PropTypes.any,
    expenseReportInvoices: React.PropTypes.array,
    jobInfo: React.PropTypes.object
  };

  getChildContext() {
    return {
      nowExpenseDataSource: this.state.nowExpenseDataSource,
      annotates: this.state.annotates,
      isAuditEditable: this.props.isAuditEditable,
      isWaitForAudit: this.props.isWaitForAudit,
      currentExpense: this.state.currentExpense,
      expenseReport: this.props.expenseReport,
      currentExpenseType: this.state.currentExpenseType,
      currentExpenseIndex: this.state.currentExpenseIndex,
      headerData: this.state.headerData,
      amountData: this.state.amountData,
      fieldsData: this.state.fieldsData,
      mergeAdjuncts: this.state.mergeAdjuncts,
      auditTab: this.state.auditTab,
      expenseReportInvoices: this.state.expenseReportInvoices,
      jobInfo:this.props.jobInfo
    };
  }

  constructor(props) {
    super(props);
    let approvedKeys = {};
    props.expenseReportInvoices.forEach(item =>
      approvedKeys[item.invoiceOID] = item.manualAudit
    );
    this.state = {
      loading: false,
      didMountLoading: true,
      currentExpense: {}, // 当前费用详情
      currentExpenseType: {},
      isShrink: false,
      annotates: [], // 批注信息
      isEdit: false, // 是否是编辑模式
      isAuditEditable: false, // 是否能够编辑
      isWaitForAudit: false,
      isNeedRefresh: false,
      showOCRFlag: false,
      headerData: {}, // 头部信息
      amountData: [], // 金额配置字段
      fieldsData: [], // 费用配置字段
      mergeAdjuncts: [], // 发票 附件 商务卡信息等
      unitInfo: {},
      expenseReportInvoices: props.expenseReportInvoices,
      randomHash: props.nowExpense.invoiceOID,
      approvedKeys: approvedKeys,
      leftWidth: props.expenseReportInvoices.length > 1 ? 650 : 600,
      ...this.initData({...props, approvedKeys})
    };
  }

  componentDidMount() {
    this.init([this.getExpenseDetail(), this.getAnnotate(), this.getExpenseType(), this.getOCRisOpen(), this.getExpenseReportChain(), this.getUnitOptions()])
      .finally(() => {
        document.addEventListener('keyup', this.handleKeyDown, true);
      });
  }

  componentWillUnmount() {
    this.props.dispatch(setCurrentExpense({}));
    document.removeEventListener('keyup', () => {}, true);
  }

  initData = ({ nowExpense, expenseReportInvoices, auditTab, approvedKeys }) => {
    const nowExpenseDataSource = expenseReportInvoices.filter(item => auditTab === 'all' ? true : approvedKeys[item.invoiceOID].toString() === auditTab);
    return {
      auditTab,
      currentInvoiceOID: nowExpense.invoiceOID,
      nowExpenseDataSource,
      currentExpenseTypeId: nowExpense.expenseTypeId,
      currentExpenseIndex: nowExpenseDataSource.findIndex(i => i.invoiceOID === nowExpense.invoiceOID),
    };
  };

  init = async (requests) => {
    this.setState({ loading: true });
    let { isAuditEditable, isWaitForAudit, showOCRFlag, unitInfo } = this.state;
    const { expenseReport, options, profile, loginUser, options: { auditBaseConfig } } = this.props;
    await Promise.all(requests)
      .then(res => {
        if (res[3]) {
          showOCRFlag = res[3].showOCRFlag;
        }

        if (res[4]) {
          let chainInfo = res[4];
          let isAuditInApproveStatus = chainInfo.chainDTO && chainInfo.chainDTO.currentFlag && chainInfo.chainDTO.nodeType === 1012;
          isWaitForAudit = this.checkNewAuth() && ((expenseReport.status === 1003 && chainInfo.prendingAudit) || isAuditInApproveStatus);
          isAuditEditable = isWaitForAudit && auditBaseConfig.reviewEditEnable;
        }

        if (res[5]){
          unitInfo = res[5]
        }
        this.setState({
          isAuditEditable,
          isWaitForAudit,
          showOCRFlag,
          annotates: res[1],
          currentExpenseType: res[2],
          currentExpense: res[0],
          randomHash: res[0].invoiceOID,
          unitInfo,
          ...ExpenseService.handleExpenseData({
            currentExpense: res[0],
            currentExpenseType: res[2],
            expenseReport,
            showOCRFlag,
            options,
            profile,
            user: loginUser,
            unitInfo
          })
        });
      })
      .catch(e => {
        errorMessage(e.response);
        this.handleBack();
      })
      .finally(() => {
        setTimeout(() => {
          this.setState({ loading: false, didMountLoading: false });
        }, 300);
      });
  };

  /**
   * 获取费用详情
   * @returns {Promise<*>}
   */
  getExpenseDetail = async () => {
    const { currentInvoiceOID } = this.state;
    const res = await baseService.getInvoiceDetail(currentInvoiceOID);
    return res.data;
  };

  /**
   * 获取发票类型
   * @returns {Promise<*>}
   */
  getExpenseType = async () => {
    const { currentExpenseTypeId } = this.state;
    const res = await baseService.getExpenseTypeById(currentExpenseTypeId);
    return res.data;
  };

  /**
   * 获取审批历史
   * @returns {Promise<*>}
   */
  getExpenseReportChain = async () => {
    const { expenseReport: { expenseReportOID } } = this.props;
    const res = await expenseReportService.getAuditChain(expenseReportOID, 1002);
    return res.data;
  };

  /**
   * 获取批注
   * @returns {Promise<*>}
   */
  getAnnotate = async () => {
    const { currentInvoiceOID } = this.state;
    return await ExpenseService.getAnnotate(currentInvoiceOID);
  };

  /**
   * 是否开通发票查验和OCR
   * @returns {Promise<*>}
   */
  getOCRisOpen = async () => {
    const { loginUser: { userOID } } = this.props;
    const res = await expenseService.getTitleList(userOID);
    return res.data;
  };

  /**
   * 获取单位值列表
   * @returns {Promise<void>}
   */
  getUnitOptions = async () => {
    const res = await expenseService.getUnitOptions();
    const obj = {};
    for (let o of res.data) {
      if (obj[o.code]) continue;
      obj[o.code] = o.messageKey;
    }
    return obj;
  };

  handleKeyDown = (e) => {
    const key_map = new Map([
      [38, this.handleUp],
      [40, this.handleDown],
      [37, () => this.refs.adjunct.handleChangeAttachment('left')],
      [39, () => this.refs.adjunct.handleChangeAttachment('right')]]);
    key_map.has(e.keyCode) && key_map.get(e.keyCode)();
  };

  getDesignationExpense = (invoiceOID) => {
    const { nowExpenseDataSource: sources } = this.state;
    const currentExpenseIndex = sources.findIndex(item => item.invoiceOID === invoiceOID);
    this.setState({
      currentExpenseIndex,
      currentInvoiceOID: invoiceOID,
      currentExpenseTypeId: sources[currentExpenseIndex].expenseTypeId,
    }, () => this.init([this.getExpenseDetail(), this.getAnnotate(), this.getExpenseType(), this.getOCRisOpen()]));
  };

  handleUp = () => {
    let { currentExpenseIndex, nowExpenseDataSource: sources } = this.state;
    if (currentExpenseIndex === 0) {
      return;
    }
    currentExpenseIndex--;
    this.setState({
      currentExpenseIndex,
      currentInvoiceOID: sources[currentExpenseIndex].invoiceOID,
      currentExpenseTypeId:  sources[currentExpenseIndex].expenseTypeId,
    }, () => this.init([this.getExpenseDetail(), this.getAnnotate(), this.getExpenseType(), this.getOCRisOpen()]));
  };

  handleDown = () => {
    let { currentExpenseIndex, nowExpenseDataSource: sources } = this.state;
    if (currentExpenseIndex === sources.length - 1) {
      return;
    }
    currentExpenseIndex++;
    this.setState({
      currentExpenseIndex,
      currentInvoiceOID: sources[currentExpenseIndex].invoiceOID,
      currentExpenseTypeId:  sources[currentExpenseIndex].expenseTypeId,
    }, () => this.init([this.getExpenseDetail(), this.getAnnotate(), this.getExpenseType(), this.getOCRisOpen()]));
  };

  handleReject = () => {
    let { currentInvoiceOID, currentExpenseIndex, nowExpenseDataSource: sources, expenseReportInvoices, auditTab } = this.state;
    if (expenseReportInvoices.length === 1) {
      this.props.afterClose({ rejectAll: true });
      return;
    }

    if (currentExpenseIndex === sources.length) currentExpenseIndex = 0;
    expenseReportInvoices.splice(sources.findIndex(item => item.invoiceOID === currentInvoiceOID), 1);
    sources.splice(sources.findIndex(item => item.invoiceOID === currentInvoiceOID), 1);

    if (!sources[0]) {
      auditTab = 'all';
      sources = expenseReportInvoices;
      currentExpenseIndex = 0;
    }

    this.setState({
      auditTab,
      isNeedRefresh: true,
      currentExpenseIndex,
      expenseReportInvoices,
      nowExpenseDataSource: sources,
      currentInvoiceOID: sources[currentExpenseIndex].invoiceOID,
      currentExpenseTypeId: sources[currentExpenseIndex].expenseTypeId,
    }, () => this.init([this.getExpenseDetail(), this.getAnnotate(), this.getExpenseType()]));
  };

  handleBack = (e, params) => {
    const { isNeedRefresh } = this.state;
    this.props.afterClose({ refresh: isNeedRefresh, ...params });
  };

  handleEdit = (refresh) => {
    this.setState({ isEdit: !this.state.isEdit, isNeedRefresh: refresh },  () => {
      if (refresh) {
        this.setState({ didMountLoading: true });
        this.init([this.getExpenseDetail(), this.getAnnotate(), this.getExpenseType()]);
      }
    });
  };

  handleShrink = () => {
    const { isShrink } = this.state;
    const { nowExpenseDataSource } = this.state;
    this.setState({
      isShrink: !isShrink,
      leftWidth: !isShrink ? 56 : nowExpenseDataSource.length > 1 ? 650 : 600
    });
  };

  handleUtil = (type) => {
    const util_map = {
      'up': this.handleUp,
      'down': this.handleDown,
      'edit': this.handleEdit,
      'back': this.handleBack
    };
    util_map[type]();
  };

  getDefaultValueByInvoice = async (receiptList) => {
    const { currentExpenseType, currentExpense: { data } } = this.state;
    if (currentExpenseType.expenseTypeOID && receiptList && receiptList.length) {
      const res = await expenseService.getDefaultValueByInvoice(currentExpenseType.id, receiptList);
      res.data && res.data.map(item => {
        data.forEach(field => {
          field.fieldOID === item.fieldOID && (field.value = item.value);
        });
      });
    }
    return data;
  };

  getRandomWord(randomFlag, min, max) {
    let str = "",
      range = min,
      arr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
    if (randomFlag) {
      range = Math.round(Math.random() * (max - min)) + min;
    }
    for (let i = 0; i < range; i++) {
      let pos = Math.round(Math.random() * (arr.length - 1));
      str += arr[pos];
    }
    return str;
  }

  handleTabChange = (auditTab) => {
    if (this.state.auditTab === auditTab) return;
    const { expenseReportInvoices } = this.props;
    const { currentInvoiceOID, approvedKeys } = this.state;
    let nowExpense = {};
    const sources = expenseReportInvoices.filter(item => auditTab === 'all' ? true : approvedKeys[item.invoiceOID].toString() === auditTab);
    sources.some(item => item.invoiceOID === currentInvoiceOID)
      ? nowExpense = sources.find(item => item.invoiceOID === currentInvoiceOID)
      : nowExpense = sources[0];
    this.setState(
      this.initData({
        auditTab,
        expenseReportInvoices,
        nowExpense,
        approvedKeys
      }), () => {currentInvoiceOID !== nowExpense.invoiceOID && this.init([this.getExpenseDetail(), this.getAnnotate(), this.getExpenseType(), this.getOCRisOpen()]);});
  };

  handleInvoiceChange = async () => {
    this.setState({ loading: true });
    let { showOCRFlag, currentExpenseType, unitInfo } = this.state;
    const { expenseReport, options, profile, loginUser } = this.props;
    const randomHash = this.getRandomWord(true, 16, 16);
    const currentExpense = await this.getExpenseDetail();
    const { amountData, mergeAdjuncts } = ExpenseService.handleExpenseData({
      currentExpense,
      currentExpenseType,
      expenseReport,
      showOCRFlag,
      options,
      profile,
      user: loginUser,
      unitInfo
    });
    this.setState({
      isNeedRefresh: true,
      randomHash,
      amountData,
      mergeAdjuncts,
      currentExpense,
      loading: false,
    });
  };

  refreshApprovedKeys = (invoiceOID, manualAudit) => {
    const { approvedKeys } = this.state;
    approvedKeys[invoiceOID] = manualAudit;
    this.setState({ approvedKeys, isNeedRefresh: true });
  };

  render() {
    const { options: { auditBaseConfig }, expenseReport, isWaitForAudit, isAuditEditable, jobInfo } = this.props;
    const { currentExpense, isShrink, leftWidth, annotates, loading, didMountLoading, randomHash, auditTab, approvedKeys, isEdit } = this.state;
    return didMountLoading
      ? <Spin style={{ margin: '20px' }} spinning={didMountLoading}/>
      : <Telescopic
        hasFooter
        leftWidth={leftWidth}
        handleShrink={this.handleShrink}
        loading={loading}
        footer={(
          <ExpenseFooter
            isReject={
              currentExpense.invoiceOID &&
              auditBaseConfig.reviewEditSuitable &&
              auditBaseConfig.expenseBatchReject &&
              [1002, 1003].includes(expenseReport.status) &&
              currentExpense.expenseTypeSubsidyType !== 1 &&
              !checkMenuDisabled()
            }
            handleBack={this.handleBack}
            invoiceOID={currentExpense.invoiceOID}
            handleReject={this.handleReject}
          />)}
      >
        <TelescopicLeft>
          <ExpenseMain
            isShrink={isShrink}
            close={this.handleBack}
            handleUtil={this.handleUtil}
            handleEdit={this.handleEdit}
            refreshAnnotate={this.getAnnotate}
            randomHash={randomHash}
            auditTab={auditTab}
            approvedKeys={approvedKeys}
            changTab={this.handleTabChange}
            refreshApprovedKeys={this.refreshApprovedKeys}
            getDesignationExpense={this.getDesignationExpense}
          />
        </TelescopicLeft>
        <TelescopicRight>
          <ExpenseAdjunct
            isShrink={isShrink}
            annotates={annotates}
            leftWidth={leftWidth}
            isWaitForAudit={isWaitForAudit}
            currentExpense={currentExpense}
            onInvoiceChange={this.handleInvoiceChange}
            refreshAnnotate={this.getAnnotate}
            randomHash={randomHash}
            ref={'adjunct'}
          />
        </TelescopicRight>
        {isEdit && (
          <AuditExpenseDetail
            visible={isEdit}
            invoiceOID={currentExpense.invoiceOID}
            expenseReportOID={expenseReport.expenseReportOID}
            isWaitForAudit={isWaitForAudit}
            isAuditEditable={isAuditEditable}
            record={currentExpense}
            info={expenseReport}
            jobInfo={jobInfo}
            showExpenseReportInvoices={[currentExpense]}
            annotateOnChange={this.getAnnotate}
            auditEditable
            close={this.handleEdit}
          />)
        }
      </Telescopic>;
  }
}


function mapStateToProps(state) {
  return {
    company: state.login.company,
    loginUser: state.login.loginUser,
    profile: state.login.profile,
    options: state.login.options,
  };
}

ExpenseDetail.propTypes = {};

export default ExpenseDetail;
